package models

import (
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
	"time"

	//	"gitee.com/lzqysoft/ilive/libs"

	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
)

type Dept struct {
	Id           int64
	Organization *Organization `orm:"rel(fk)"`
	Name         string        `orm:"column(name)"`
	Remark       string        `orm:"column(remark);null"`
	Pid          int64         `orm:"column(pid)"`
	Level        int64         `orm:"column(level)"`
	Seq          int64         `orm:"column(seq)"`
	Status       int64         `orm:"column(status)"`
	Isdelete     int64         `orm:"column(isdelete)"`
	Ctime        time.Time     `orm:"column(ctime);type(timestamp without time zone)"`
	Creater      string        `orm:"column(creater)"`
	Utime        time.Time     `orm:"column(utime);type(timestamp without time zone)"`
	Updater      string        `orm:"column(updater)"`
	User         []*User       `orm:"reverse(many)"`
}

func (t *Dept) TableName() string {
	return "dept"
}

func init() {
	orm.RegisterModel(new(Dept))
}

// AddDept insert a new Dept into database and returns
// last inserted Id on success.
func AddDept(m *Dept) (id int64, err error) {
	o := orm.NewOrm()
	id, err = o.Insert(m)
	return
}

// GetDeptById retrieves Dept by Id. Returns error if
// Id doesn't exist
func GetDeptById(id int64) (v *Dept, err error) {
	o := orm.NewOrm()
	v = &Dept{Id: id}
	if err = o.Read(v); err == nil {
		o.LoadRelated(v, "Organization")
		o.LoadRelated(v, "User")
		return v, nil
	}
	return nil, err
}

// GetAllDept retrieves all Dept matches certain condition. Returns empty list if
// no records exist
func GetAllDept(query map[string]string, fields []string, sortby []string, order []string,
	offset int64, limit int64) (ml []interface{}, err error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Dept))
	// query k=v
	for k, v := range query {
		// rewrite dot-notation to Object__Attribute
		k = strings.Replace(k, ".", "__", -1)
		qs = qs.Filter(k, v)
	}
	qs = qs.Filter("Isdelete", 0)
	// order by:
	var sortFields []string
	if len(sortby) != 0 {
		if len(sortby) == len(order) {
			// 1) for each sort field, there is an associated order
			for i, v := range sortby {
				orderby := ""
				if order[i] == "desc" {
					orderby = "-" + v
				} else if order[i] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
			qs = qs.OrderBy(sortFields...)
		} else if len(sortby) != len(order) && len(order) == 1 {
			// 2) there is exactly one order, all the sorted fields will be sorted by this order
			for _, v := range sortby {
				orderby := ""
				if order[0] == "desc" {
					orderby = "-" + v
				} else if order[0] == "asc" {
					orderby = v
				} else {
					return nil, errors.New("Error: Invalid order. Must be either [asc|desc]")
				}
				sortFields = append(sortFields, orderby)
			}
		} else if len(sortby) != len(order) && len(order) != 1 {
			return nil, errors.New("Error: 'sortby', 'order' sizes mismatch or 'order' size is not 1")
		}
	} else {
		if len(order) != 0 {
			return nil, errors.New("Error: unused 'order' fields")
		}
	}

	var l []orm.Params
	qs = qs.RelatedSel().OrderBy(sortFields...)
	if _, err = qs.Limit(limit, offset).Values(&l, fields...); err == nil {
		if len(fields) == 0 {
			for _, v := range l {
				u, _ := GetDeptById(v["Id"].(int64))
				r, err := GetDeptById(v["Pid"].(int64))
				if err == nil && len(r.Name) > 0 {
					v["Pname"] = r.Name
				} else {
					v["Pname"] = "顶级部门"
				}
				v["OrgId"] = u.Organization.Id
				v["OrgName"] = u.Organization.Name
				ml = append(ml, v)
			}
		} else {
			// trim unused fields
			for _, v := range l {
				m := make(map[string]interface{})
				val := reflect.ValueOf(v)
				for _, fname := range fields {
					m[fname] = val.FieldByName(fname).Interface()
				}
				ml = append(ml, m)
			}
		}
		return ml, nil
	}
	return nil, err
}

// UpdateDept updates Dept by Id and returns error if
// the record to be updated doesn't exist
func UpdateDeptById(m *Dept) (err error) {
	o := orm.NewOrm()
	v := Dept{Id: m.Id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		var num int64
		if num, err = o.Update(m); err == nil {
			fmt.Println("Number of records updated in database:", num)
		}
	}
	return
}

// DeleteDept deletes Dept by Id and returns error if
// the record to be deleted doesn't exist
func DeleteDept(id int64) (err error) {
	o := orm.NewOrm()
	v := Dept{Id: id}
	// ascertain id exists in the database
	if err = o.Read(&v); err == nil {
		//清空该部门下的人员
		cleanUser(id)
		//修改子部门
		changeChildrenDept(id)
		var num int64
		if num, err = o.Delete(&Dept{Id: id}); err == nil {
			fmt.Println("Number of records deleted in database:", num)

		}
	}
	return
}

// 软删除部门 Dept by Id and returns error if
// the record to be deleted doesn't exist
func SoftDeleteDept(id int64, uname string) (err error) {
	o := orm.NewOrm()

	//	err = o.Begin() // 事务处理过程

	v := Dept{Id: id}
	if err = o.Read(&v); err == nil {
		v.Isdelete = 1
		v.Updater = uname
		v.Utime = time.Now()
		_, err = o.Update(&v)
	}

	return
}

//Desc 根据单位获取部门树
//Param OrgId 单位id
//return 部门树，异常
func GetDeptByOrgId(oid int64) (dlist []Dept, err error) {
	o := orm.NewOrm()
	if _, err = o.QueryTable("dept").Filter("Organization", oid).RelatedSel().Filter("isdelete", 0).Filter("status", 1).OrderBy("Seq").Limit(-1).All(&dlist); err == nil {
		return dlist, nil
	} else {
		return nil, err
	}

}

//Desc 根据上级部门id与单位id构造部门树
//Param parentId 上级部门id
//Param OrgId 单位id
//return 部门树
func GetDeptTreeByParentIdAndOrgId(parentId int64, orgId int64) (nodes []map[string]interface{}) {
	sum, err, data := GetDeptByParentAndOrgId(parentId, orgId)
	if sum != 0 && err == nil && data != nil {
		for _, val := range data {
			var node = make(map[string]interface{})
			node["id"] = val["id"]
			node["oid"] = val["org_id"]
			node["expand"] = true
			node["name"] = val["name"]
			node["pid"] = val["pid"]
			node["title"] = val["name"]
			pid, _ := strconv.ParseInt(val["id"].(string), 10, 64)
			node["children"] = GetDeptTreeByParentIdAndOrgId(pid, orgId)
			nodes = append(nodes, node)
		}
	}
	return
}

//Desc 根据上级部门id与单位id查询
//Param parentId 上级部门id
//Param orgId 单位id
//return []orm.Params
func GetDeptByParentAndOrgId(parentId, orgId int64) (int64, error, []orm.Params) {
	var maps []orm.Params
	var sql = "SELECT * FROM public.dept ta WHERE ta.pid = ? AND ta.org_id= ? and ta.isdelete=0 and ta.status=1"
	o := orm.NewOrm()
	sum, err := o.Raw(sql, parentId, orgId).Values(&maps)
	return sum, err, maps
}

//Desc 根据上级部门id
//Param parentId 上级部门id
//return []Dept
func GetDeptByPid(parentId int64) (err error, dlist []Dept) {
	o := orm.NewOrm()
	if _, err := o.QueryTable("dept").Filter("Isdelete", 0).Filter("pid", parentId).All(&dlist); err == nil {
		return nil, dlist
	} else {
		return err, nil
	}
}

//Desc 根据部门名称获取部门
//Param name 部门名称
//Param orgId 单位id
//return Dept
func GetDeptByName(name string, oid int64) (v Dept, err error) {
	o := orm.NewOrm()
	qs := o.QueryTable(new(Dept))
	beego.Debug(name, oid)
	err = qs.Filter("Organization__ID", oid).Filter("Name", name).One(&v)

	return

}

//Desc 清除部门下的人员
//Param deptId 部门id
func cleanUser(deptId int64) {
	o := orm.NewOrm()
	o.QueryTable("user_dept").Filter("dept_id", deptId).Update(orm.Params{"dept_id": 0})
}

//Desc 修改了部门
//Param deptId 部门id
func changeChildrenDept(id int64) {
	o := orm.NewOrm()
	o.QueryTable("dept").Filter("pid", id).Update(orm.Params{"pid": 0})
}

////通过DeptId 获取 UserDept
//func GetUserDeptByDeptId(id int64) (userdept []UserDept, err error) {
//	o := orm.NewOrm()
//	qs := o.QueryTable("user_dept").Filter("dept_id", id).Limit(-1)
//	_, err = qs.All(&userdept)
//	if err == nil {
//		return userdept, nil
//	}
//	return nil, err
//}

//Desc 根据用户删除用户部门关系
//Param userId 用户id
//return error
func DeleteUserDeptByUserId(userId int64) error {
	o := orm.NewOrm()
	sql := "DELETE FROM public.user_dept ta WHERE ta.user_id = ?"
	_, err := o.Raw(sql, userId).Exec()
	return err
}

//Desc 根据用户单位删除用户部门关系
//Param oid 单位id
//return error
func DeleteUserDeptByOrg(oid int64) (err error) {
	o := orm.NewOrm()
	sql := "DELETE  FROM  user_depts a  where a.dept_id in" +
		" ( select b.id from dept b where b.Organization_id= ? )"
	_, err = o.Raw(sql, oid).Exec()
	return
}

//Desc 批量设置用户部门关系
//Param []deptId 部门id
//Param users 用户id
//return error
func SetUserDept(deptId int64, users []string) error {
	//	sql := "UPDATE user_dept SET dept_id=? WHERE id in (?)"
	//	s := strings.Join(users, ",")
	//	fmt.Println("========users is :", s)
	o := orm.NewOrm()
	//	_, err := o.Raw(sql, deptId, s).Exec()
	_, err := o.QueryTable("user_dept").Filter("user_id__in", users).Update(orm.Params{"dept_id": deptId})
	return err
}

//Desc 获取用户部门树
//Param oid 单位id
//return error
func GetUserDeptTree(oid int64) (nodes []map[string]interface{}, err error) {
	depts, err := GetDeptByOrgId(oid)
	for _, v := range depts {
		us, _ := GetUserByDept(v.Id)
		beego.Debug(v.Id, us)
		for _, e := range us {
			var nod = make(map[string]interface{})
			nod["id"] = e.Id
			userprof, _ := GetUserprofById(e.Id)
			//			u, _ := GetUserById(e.UserId)
			nod["name"] = userprof.Title
			nod["pId"] = v.Id
			nod["drop"] = false
			if e.Isdelete == 0 && e.Status == 1 {
				nodes = append(nodes, nod)
			}

		}
		var node = make(map[string]interface{})
		node["id"] = v.Id
		node["name"] = v.Name
		node["pId"] = v.Pid
		node["isParent"] = true
		node["drag"] = false
		//		node["drop"] = true
		node["open"] = true
		nodes = append(nodes, node)
		var hnode = make(map[string]interface{})
		hnode["id"] = "isHidden" + v.Name
		hnode["name"] = "isHidden" + v.Name
		hnode["pId"] = v.Id
		hnode["isHidden"] = true
		nodes = append(nodes, hnode)

	}

	return
}

//分配部门用户
func AddUserDept(deptid int64, userid int64) (int64, error) {
	o := orm.NewOrm()
	dept := Dept{Id: deptid}
	user := User{Id: userid}
	m2m := o.QueryM2M(&user, "Dept")
	num, err := m2m.Add(&dept)
	return num, err
}

//Desc 递归获取全部下级部门id
//Param 部门id ,pids *[]int64
//return pids *[]int64
func GetChildrenDept(id int64, ids *[]int64) {
	o := orm.NewOrm()
	var dept []Dept
	qs := o.QueryTable("Dept").Filter("pid", id).Filter("Isdelete", 0).Filter("status", 1)
	count, _ := qs.Limit(-1).All(&dept)
	if count > 0 {
		for _, v := range dept {
			*ids = append(*ids, v.Id)
			GetChildrenDept(v.Id, ids)
		}
	}

}

//Desc 获取全部下级部门的id
//Param 部门id
//return str
func GetDeptChildrenStr(id int64) *[]int64 {
	ids := new([]int64)
	GetChildrenDept(id, ids)
	*ids = append(*ids, id)

	return ids
}

//Desc 获取全部下级部门的过滤sql
//Param 部门id
//return str
func GetDeptSql(id int64) (sql string) {
	eds := GetDeptChildrenStr(id)
	sql = fmt.Sprintf(" and dept.id in %v", eds)
	return
}
